package com.cci.kangdao.crmapi;

import com.cci.kangdao.utilTool.HttpUtils;
import com.cci.kangdao.utilTool.JsonUtils;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.apache.http.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import javax.net.ssl.SSLException;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class CRMHttpClientUtil {

	/** 1、日志 */
	private static final Logger LOG = Logger.getLogger(CRMHttpClientUtil.class);
	/** 2、请求参数配置 */
	private static RequestConfig requestConfig = null;

	static {
        //设置http的状态参数
        requestConfig = RequestConfig.custom()
                .setSocketTimeout(30000)
                .setConnectTimeout(30000)
                .setConnectionRequestTimeout(30000)
                .build();

    }

	/**
	 * 1、 HTTP GET REQUEST
	 * @author: leonbreeze
	 * @Description: TODO
	 * @param urlString
	 * @param headerMap
	 * @param parameter
	 * @return
	 * @date:   Feb 11, 2019 1:33:53 PM
	 * @return: JSONObject
	 * @throws
	 */
	public static JSONObject httpGETRequest(String urlString, Map<String,Object> headerMap,Map<String,Object> parameter) {

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse htpResponse = null;
		JSONObject responseBody = null;

		// 创建客户端
		if (urlString.startsWith(CRMServiceConst.CRM_URL_HTTPS)) {
            /** https访问 */
			httpClient = getClient(true);

			//httpClient = MySSLSocketFactory.getNewHttpClient();
//            httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
        } else {
            /** 普通的http调用 */
            httpClient = HttpClients.createDefault();
        }

        String urlPath = getAbsolutelyUrlPath(urlString, parameter);
        //创建一个get请求
        HttpGet httpget = new HttpGet(urlPath);

        /** 添加请求头数据 */
		if (headerMap != null) {

			Set<Map.Entry<String, Object>> headerEntrySet = headerMap.entrySet();
			if (headerEntrySet.size() > 0) {
				for (Map.Entry<String, Object> header : headerEntrySet) {
					String headerName = header.getKey();
					String headerValue = header.getValue().toString();
					// 依次添加请求头
					httpget.addHeader(headerName, headerValue);
				}
			}

		}

        httpget.setConfig(requestConfig);

        try {
            //发送请求并获取返回结果
        	htpResponse = httpClient.execute(httpget);

            if(htpResponse.getStatusLine().getStatusCode() == CRMServiceConst.CRM_RESPONSE_CODE_SUCCESS){//判断状态码
                HttpEntity httpEntity = htpResponse.getEntity(); //获取返回body
                String resBody = EntityUtils.toString(httpEntity,CRMServiceConst.CRM_RESPONSE_ENCODE_UTF8);// 转成string
                responseBody = JSONObject.fromObject(resBody);
                LOG.info("调用返回body:"+ resBody);
            }else {
            	LOG.info("调用返回状态码:"+ htpResponse.getStatusLine());
            	LOG.info("http 返回的内容是\n" + EntityUtils.toString(htpResponse.getEntity(), CRMServiceConst.CRM_RESPONSE_ENCODE_UTF8));
            	responseBody = new JSONObject();
            	responseBody.put("status", htpResponse.getStatusLine().getStatusCode());
            	responseBody.put("msg", htpResponse.getStatusLine().getReasonPhrase());
				responseBody.put("data",new JSONObject());
            }
        } catch(Exception e){
			LOG.error(e);
			responseBody = new JSONObject();
			responseBody.put("status", 600);//自定义http code
			responseBody.put("msg", e.getMessage());
			responseBody.put("data",new JSONObject());
        }finally {
            try{
                if(htpResponse != null){
                	htpResponse.close(); //释放连接
                }
            }catch(Exception e){}
            try{
                if(httpClient != null){
                	httpClient.close();//关闭客户端
                }
            }catch(Exception e){}
        }

		return responseBody;
	}

	/**
	 * @param isPooled 是否使用连接池
	 */
	public static CloseableHttpClient getClient(boolean isPooled) {
		HttpRequestRetryHandler handler = new HttpRequestRetryHandler() {
			@Override
			public boolean retryRequest(IOException arg0, int retryTimes, HttpContext arg2) {
				if (retryTimes > 3) {
					return false;
				}
				if (arg0 instanceof UnknownHostException || arg0 instanceof ConnectTimeoutException
						|| !(arg0 instanceof SSLException) || arg0 instanceof NoHttpResponseException) {
					return true;
				}

				HttpClientContext clientContext = HttpClientContext.adapt(arg2);
				HttpRequest request = clientContext.getRequest();
				boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
				if (idempotent) {
					// 如果请求被认为是幂等的，那么就重试。即重复执行不影响程序其他效果的
					return true;
				}
				return false;
			}
		};


		if (isPooled) {
			return HttpClients.custom().setRetryHandler(handler).build();
		}
		return HttpClients.createDefault();
	}

	/**
	 * 2、 HTTP POST REQUEST
	 * @author: leonbreeze
	 * @Description: HTTP REQUEST POST
	 * @param urlString
	 * @param headerMap
	 * @param parameter
	 * @date:   Feb 11, 2019 12:39:00 PM
	 * @return: void
	 * @throws
	 */
	public static JSONObject httpPOSTRequest(String urlString, Map<String,Object> headerMap,Map<String,Object> parameter){

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse htpResponse = null;
		JSONObject responseBody = null;

		LOG.info("同步到CRM系统url:" + urlString + ",参数信息："+JsonUtils.toJsonString(parameter)
				+"请求头信息："+JsonUtils.toJsonString(headerMap));
		RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(60000)
				.setSocketTimeout(60000).setConnectTimeout(60000).build();
		HttpPost httpPost = new HttpPost(urlString);
		httpPost.setConfig(requestConfig);
		/** 添加请求头数据 */
		if (CRMServiceConst.IS_CRMHEADER_ADDMD5) {
			if (headerMap != null){
				Set<Map.Entry<String, Object>> headerEntrySet = headerMap.entrySet();
				if (headerEntrySet.size() > 0) {
					for (Map.Entry<String, Object> header : headerEntrySet) {
						String headerName = header.getKey();
						String headerValue = header.getValue().toString();
						// 依次添加请求头
						if (headerName.equals("Content-Type")){continue;}
						httpPost.addHeader(headerName, headerValue);
					}
				}
			}

		}

        if (urlString.startsWith(CRMServiceConst.CRM_URL_HTTPS)) {
            /** https访问 */
			httpClient = getClient(true);
			//httpClient = MySSLSocketFactory.getNewHttpClient();

//			httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
        } else {
            /** 普通的http调用 */
            httpClient = HttpClients.createDefault();

        }

        try {

			HttpEntity reqEntity = null;
        	if (headerMap != null && headerMap.containsKey("Content-Type")
					&& (headerMap.get("Content-Type").equals("CCI")||headerMap.get("Content-Type").equals("XCEC"))){
				JSONObject jsonBodyParameter = JSONObject.fromObject(parameter);
				reqEntity = new StringEntity(jsonBodyParameter.toString(),ContentType.APPLICATION_JSON);
			}else if (headerMap != null && headerMap.containsKey("Content-Type")
					&& (headerMap.get("Content-Type").equals("EngineRelation"))){
				Object params = parameter.get("params");
				JSONObject jsonBodyParameter = JSONObject.fromObject(params);
				reqEntity = new StringEntity(jsonBodyParameter.toString(),ContentType.APPLICATION_JSON);
			}else
			{
				/** 遍历参数，构造List(NameValuePair) */
				List<NameValuePair> formparams = new ArrayList<NameValuePair>();
				Set<Map.Entry<String, Object>> entrySet = parameter.entrySet();
				for (Map.Entry<String, Object> e : entrySet) {
					String name = e.getKey();
					Object value = e.getValue();
					NameValuePair pair = new BasicNameValuePair(name, (String) value);
					formparams.add(pair);
				}
				reqEntity = new UrlEncodedFormEntity(formparams, CRMServiceConst.CRM_RESPONSE_ENCODE_UTF8);
			}
        	httpPost.setEntity(reqEntity);
        	httpPost.setConfig(requestConfig);
			try {
				LOG.error("httpClient.execute执行前："+ LocalDateTime.now()
						+ ",activeCount:"+Thread.currentThread().getThreadGroup().activeCount()
						+ ",activeGroupCount:"+Thread.currentThread().getThreadGroup().activeGroupCount());
				htpResponse = httpClient.execute(httpPost);
				LOG.error("httpClient.execute执行后："+ LocalDateTime.now()
						+ ",activeCount:"+Thread.currentThread().getThreadGroup().activeCount()
						+ ",activeGroupCount:"+Thread.currentThread().getThreadGroup().activeGroupCount());
				//....do more work...
			} catch (SocketTimeoutException | ConnectTimeoutException ex) {
				LOG.error("请求连接超时,请求路径为:"+urlString);
			} catch (Exception ex) {
				LOG.error("请求异常，异常信息：" + ex.getMessage());
				ex.printStackTrace();
			}



        	if (htpResponse.getStatusLine().getStatusCode() == CRMServiceConst.CRM_RESPONSE_CODE_SUCCESS) {
                HttpEntity resEntity = htpResponse.getEntity();
				String resBody = EntityUtils.toString(resEntity, CRMServiceConst.CRM_RESPONSE_ENCODE_UTF8);
				/** 将String数组转为JSON*/
				responseBody = JSONObject.fromObject(resBody);
				LOG.info("调用返回body:"+ resBody);
            } else {
            	LOG.info("调用返回状态码:"+ htpResponse.getStatusLine());
            	LOG.info("http 返回的内容是\n" + htpResponse.getEntity());
            	responseBody = new JSONObject();
            	responseBody.put("status", htpResponse.getStatusLine().getStatusCode());
            	responseBody.put("msg", htpResponse.getStatusLine().getReasonPhrase());
				responseBody.put("data",new JSONObject());
            }
        	/*//自测时模拟挂号失败情况
			responseBody.put("status", 2);
			responseBody.put("msg", "test 挂号失败原因");
			responseBody.put("data",new JSONObject());*/
        }catch(Exception e) {
        	LOG.error("crm request exception"+e);
        	LOG.error("最外层报错catch-e.getMessage():"+e.getMessage());
			responseBody = new JSONObject();
			responseBody.put("status", 600);//自定义http code
			responseBody.put("msg", e.getMessage());
			responseBody.put("data",new JSONObject());
        } finally {
        	try {
        		if(htpResponse != null){
        			htpResponse.close(); //释放连接
                }

			} catch (IOException e) {
				e.printStackTrace();
			}
        	try{
                if(httpClient != null){
                	httpClient.close();//关闭客户端
                }
            }catch(Exception e){}
        }
		LOG.info("请求接口返回responseBody:" + (null != responseBody ? responseBody.toString() : ""));
        return responseBody;
	}

	/**
	 * 2、 HTTP POST REQUEST  xcec单独使用
	 *
	 * @param urlString
	 * @param headerMap
	 * @param parameter
	 * @throws
	 * @author: leonbreeze
	 * @Description: HTTP REQUEST POST
	 * @date: Feb 11, 2019 12:39:00 PM
	 * @return: void
	 */
	public static JSONObject httpPOSTRequestXCEC(String urlString, Map<String, Object> headerMap, Map<String, Object> parameter) {

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse htpResponse = null;
		JSONObject responseBody = null;

		LOG.info("同步到CRM系统url:" + urlString + ",参数信息：" + JsonUtils.toJsonString(parameter)
				+ "请求头信息：" + JsonUtils.toJsonString(headerMap));
		RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(60000)
				.setSocketTimeout(60000).setConnectTimeout(60000).build();
		HttpPost httpPost = new HttpPost(urlString);
		httpPost.setConfig(requestConfig);
		/** 添加请求头数据 */
		if (CRMServiceConst.IS_CRMHEADER_ADDMD5) {
			if (headerMap != null) {
				Set<Map.Entry<String, Object>> headerEntrySet = headerMap.entrySet();
				if (headerEntrySet.size() > 0) {
					for (Map.Entry<String, Object> header : headerEntrySet) {
						String headerName = header.getKey();
						String headerValue = header.getValue().toString();
						// 依次添加请求头
						if (headerName.equals("Content-Type")) {
							continue;
						}
						httpPost.addHeader(headerName, headerValue);
					}
				}
			}

		}

		if (urlString.startsWith(CRMServiceConst.CRM_URL_HTTPS)) {
			/** https访问 */
			httpClient = getClient(true);

			//httpClient = MySSLSocketFactory.getNewHttpClient();

//			httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier()).build();
		} else {
			/** 普通的http调用 */
			httpClient = HttpClients.createDefault();

		}
		String exceptionmsg = null;
		try {

			HttpEntity reqEntity = null;
			if (headerMap != null && headerMap.containsKey("Content-Type")
					&& (headerMap.get("Content-Type").equals("CCI") || headerMap.get("Content-Type").equals("XCEC"))) {
				JSONObject jsonBodyParameter = JSONObject.fromObject(parameter);
				reqEntity = new StringEntity(jsonBodyParameter.toString(), ContentType.APPLICATION_JSON);
			} else if (headerMap != null && headerMap.containsKey("Content-Type")
					&& (headerMap.get("Content-Type").equals("EngineRelation"))) {
				Object params = parameter.get("params");
				JSONObject jsonBodyParameter = JSONObject.fromObject(params);
				reqEntity = new StringEntity(jsonBodyParameter.toString(), ContentType.APPLICATION_JSON);
			} else {
				/** 遍历参数，构造List(NameValuePair) */
				List<NameValuePair> formparams = new ArrayList<NameValuePair>();
				Set<Map.Entry<String, Object>> entrySet = parameter.entrySet();
				for (Map.Entry<String, Object> e : entrySet) {
					String name = e.getKey();
					Object value = e.getValue();
					NameValuePair pair = new BasicNameValuePair(name, (String) value);
					formparams.add(pair);
				}
				reqEntity = new UrlEncodedFormEntity(formparams, CRMServiceConst.CRM_RESPONSE_ENCODE_UTF8);
			}
			httpPost.setEntity(reqEntity);
			httpPost.setConfig(requestConfig);
			try {
				LOG.error("httpClient.execute执行前：" + LocalDateTime.now()
						+ ",activeCount:" + Thread.currentThread().getThreadGroup().activeCount()
						+ ",activeGroupCount:" + Thread.currentThread().getThreadGroup().activeGroupCount());
				htpResponse = httpClient.execute(httpPost);
				LOG.error("httpClient.execute执行后：" + LocalDateTime.now()
						+ ",activeCount:" + Thread.currentThread().getThreadGroup().activeCount()
						+ ",activeGroupCount:" + Thread.currentThread().getThreadGroup().activeGroupCount());
				//....do more work...
			} catch (SocketTimeoutException | ConnectTimeoutException ex) {
				LOG.error("请求连接超时,请求路径为:" + urlString);
				exceptionmsg = ex.getMessage();
			} catch (Exception ex) {
				LOG.error("请求异常，异常信息：" + ex.getMessage());
				ex.printStackTrace();
				exceptionmsg = ex.getMessage();
			}


			if (htpResponse.getStatusLine().getStatusCode() == CRMServiceConst.CRM_RESPONSE_CODE_SUCCESS) {
				HttpEntity resEntity = htpResponse.getEntity();
				String resBody = EntityUtils.toString(resEntity, CRMServiceConst.CRM_RESPONSE_ENCODE_UTF8);
				/** 将String数组转为JSON*/
				responseBody = JSONObject.fromObject(resBody);
				LOG.info("调用返回body:" + resBody);
			} else {
				LOG.info("调用返回状态码:" + htpResponse.getStatusLine());
				LOG.info("http 返回的内容是\n" + htpResponse.getEntity());
				responseBody = new JSONObject();
				responseBody.put("status", htpResponse.getStatusLine().getStatusCode());
				responseBody.put("msg", htpResponse.getStatusLine().getReasonPhrase());
				responseBody.put("data", new JSONObject());
			}
        	/*//自测时模拟挂号失败情况
			responseBody.put("status", 2);
			responseBody.put("msg", "test 挂号失败原因");
			responseBody.put("data",new JSONObject());*/
		} catch (Exception e) {
			LOG.error("crm request exception" + e);
			LOG.error("最外层报错catch-e.getMessage():" + e.getMessage());
			responseBody = new JSONObject();
			responseBody.put("status", 600);//自定义http code
			responseBody.put("msg", org.apache.commons.lang3.StringUtils.isNotBlank(exceptionmsg) ? exceptionmsg : e.getMessage());
			responseBody.put("data", new JSONObject());
		} finally {
			try {
				if (htpResponse != null) {
					htpResponse.close(); //释放连接
				}

			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if (httpClient != null) {
					httpClient.close();//关闭客户端
				}
			} catch (Exception e) {
			}
		}
		return responseBody;
	}


	/**
	 * @author: leonbreeze
	 * @Description: 根据url和参数获取全路径
	 * @param urlString
	 * @param parameter
	 * @return
	 * @date:   Feb 11, 2019 1:14:50 PM
	 * @return: String
	 * @throws
	 */
	private static String getAbsolutelyUrlPath(String urlString, Map<String,Object> parameter){

		String parameterPath = "";
		if (parameter != null && !parameter.isEmpty()) {
			Set<Map.Entry<String, Object>> entrySet = parameter.entrySet();
	        for (Map.Entry<String, Object> e : entrySet) {
	            String name = e.getKey();
	            Object value = e.getValue();
	            parameterPath = (parameterPath + name + "=" + value + "&");
	        }
	        if (!parameterPath.startsWith("?")) {
	        	parameterPath = "?" + parameterPath;
	        }
	        if (parameterPath.endsWith("&")) {
	        	parameterPath = parameterPath.substring(0,parameterPath.length() - 1);
	        }
		}

		return urlString + parameterPath;
	}

    /**
     * DCEC专用Post请求
     *
     * @param channelHost url地址
     * @param token       Authorization
     * @param jsonString  传参
     * @return
     */
    public static JSONObject httpPOSTRequestForDCEC(String channelHost, String token, String jsonString) {
        Header tokenHeader = new BasicHeader("Authorization", token);
		JSONObject jsonObject = null;
        try {
			LOG.info("DCEC接口访问情况：请求链接: " + channelHost + "; 请求参数" + jsonString);
			String response = HttpUtils.postJson(channelHost, jsonString, new ResponseHandler<String>() {
				@Override
				public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
					if (response.getStatusLine().getStatusCode() == 200
							|| response.getStatusLine().getStatusCode() == 206) {
						HttpEntity httpEntity = response.getEntity();
						return EntityUtils.toString(httpEntity);
					} else {
						LOG.info("调用返回状态码:" + response.getStatusLine());
						LOG.error("DCEC接口异常: 请求链接: " + channelHost + "; 请求参数：" + jsonString
								+ "；返回结果：" + response);
						JSONObject responseBody = new JSONObject();
						responseBody.put("status", response.getStatusLine().getStatusCode());
						responseBody.put("msg", response.getStatusLine().getReasonPhrase());
						responseBody.put("data", new JSONObject());
						return responseBody.toString();
					}
				}
			}, tokenHeader);
			LOG.info("DCEC接口访问情况：请求链接: " + channelHost + "; 返回参数" + response);
			if (StringUtils.isNotEmpty(response)) {
				DCECResponse baseResponse = JsonUtils.toJavaObject(response, DCECResponse.class);
				jsonObject = new JSONObject();
				jsonObject.put("status", baseResponse.getStatus());//自定义http code
				jsonObject.put("msg", baseResponse.getMsg());
				jsonObject.put("data", baseResponse.getData());
			}
		}catch (Exception e){
			LOG.error(e.getMessage(), e);
			jsonObject = new JSONObject();
			jsonObject.put("status", 600);//自定义http code
			jsonObject.put("msg", e.getMessage());
			jsonObject.put("data", new JSONObject());
		} finally {
        	if(null == jsonObject){
				jsonObject = new JSONObject();
				jsonObject.put("status", 800);//自定义http code
				jsonObject.put("msg", "DCEC接口异常");
				jsonObject.put("data", new JSONObject());
			}
		}
		return jsonObject;
	}

}

